unit Pianopas;

interface
 uses

     FMX.Graphics,
     FMX.Objects,
     FMX.StdCtrls,
      system.classes,
      system.UITypes,
      system.SysUtils,
      system.Types,
      fmx.Types,
      FMX.Media,
      fmx.Dialogs;

 type
     tkeyType=(white,black);

      tpianokey=record
           keyButton:timage;
           KeyType:tkeyType;
           isPlay:boolean;
           pAudio:TMediaPlayer;
      end;

      Ttimbre=record
         TimbreLabel:TRadioButton;
         Path:string;
         Pretimbre:tstringlist;
      end;

      TPiano=class

            PreAudio:tstringlist;
            PianoKey :array[0..87] of tpianokey;
            timbre:array of ttimbre;
            timbreCaption:tlabel;
            constructor Create(backG:TObject);
            procedure PreLoadAudio(APath:string;const Eix:string='*.wav');
            procedure play(KeyIndex:integer);
            private
            backbox:TRectangle;
            timbrePath:string;
            function FindPathFiles(const APath: string; const APropty: String = '*.mp3'):tstringlist;
            function GettimbreList():tstringlist;
            procedure MDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: single);
            procedure MUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: single);
            procedure onChange(Sender: TObject);

            procedure KeyClick(Sender: TObject);

                const
                    keylist:array of string =['white,01,A,Big,2,Group',
                                              'black,02,A#,Big,2,Group',
                                              'white,03,B,Big,2,Group',
                                              'white,04,C,Big,1,Group',
                                              'black,05,C#,Big,1,Group',
                                              'white,06,D,Big,1,Group',
                                              'black,07,D#,Big,1,Group',
                                              'white,08,E,Big,1,Group',
                                              'white,09,F,Big,1,Group',
                                              'black,10,F#,Big,1,Group',
                                              'white,11,G,Big,1,Group',
                                              'black,12,G#,Big,1,Group',
                                              'white,13,A,Big,1,Group',
                                              'black,14,A#,Big,1,Group',
                                              'white,15,B,Big,1,Group',
                                              'white,16,C,Big,0,Group',
                                              'black,17,C#,Big,0,Group',
                                              'white,18,D,Big,0,Group',
                                              'black,19,D#,Big,0,Group',
                                              'white,20,E,Big,0,Group',
                                              'white,21,F,Big,0,Group',
                                              'black,22,F#,Big,0,Group',
                                              'white,23,G,Big,0,Group',
                                              'black,24,G#,Big,0,Group',
                                              'white,25,A,Big,0,Group',
                                              'black,26,A#,Big,0,Group',
                                              'white,27,B,Big,0,Group',
                                              'white,28,C,Small,0,Group',
                                              'black,29,C#,Small,0,Group',
                                              'white,30,D,Small,0,Group',
                                              'black,31,D#,Small,0,Group',
                                              'white,32,E,Small,0,Group',
                                              'white,33,F,Small,0,Group',
                                              'black,34,F#,Small,0,Group',
                                              'white,35,G,Small,0,Group',
                                              'black,36,G#,Small,0,Group',
                                              'white,37,A,Small,0,Group',
                                              'black,38,A#,Small,0,Group',
                                              'white,39,B,Small,0,Group',
                                              'white,40,C,Small,1,Group',
                                              'black,41,C#,Small,1,Group',
                                              'white,42,D,Small,1,Group',
                                              'black,43,D#,Small,1,Group',
                                              'white,44,E,Small,1,Group',
                                              'white,45,F,Small,1,Group',
                                              'black,46,F#,Small,1,Group',
                                              'white,47,G,Small,1,Group',
                                              'black,48,G#,Small,1,Group',
                                              'white,49,A,Small,1,Group',
                                              'black,50,A#,Small,1,Group',
                                              'white,51,B,Small,1,Group',
                                              'white,52,C,Small,2,Group',
                                              'black,53,C#,Small,2,Group',
                                              'white,54,D,Small,2,Group',
                                              'black,55,D#,Small,2,Group',
                                              'white,56,E,Small,2,Group',
                                              'white,57,F,Small,2,Group',
                                              'black,58,F#,Small,2,Group',
                                              'white,59,G,Small,2,Group',
                                              'black,60,G#,Small,2,Group',
                                              'white,61,A,Small,2,Group',
                                              'black,62,A#,Small,2,Group',
                                              'white,63,B,Small,2,Group',
                                              'white,64,C,Small,3,Group',
                                              'black,65,C#,Small,3,Group',
                                              'white,66,D,Small,3,Group',
                                              'black,67,D#,Small,3,Group',
                                              'white,68,E,Small,3,Group',
                                              'white,69,F,Small,3,Group',
                                              'black,70,F#,Small,3,Group',
                                              'white,71,G,Small,3,Group',
                                              'black,72,G#,Small,3,Group',
                                              'white,73,A,Small,3,Group',
                                              'black,74,A#,Small,3,Group',
                                              'white,75,B,Small,3,Group',
                                              'white,76,C,Small,4,Group',
                                              'black,77,C#,Small,4,Group',
                                              'white,78,D,Small,4,Group',
                                              'black,79,D#,Small,4,Group',
                                              'white,80,E,Small,4,Group',
                                              'white,81,F,Small,4,Group',
                                              'black,82,F#,Small,4,Group',
                                              'white,83,G,Small,4,Group',
                                              'black,84,G#,Small,4,Group',
                                              'white,85,A,Small,4,Group',
                                              'black,86,A#,Small,4,Group',
                                              'white,87,B,Small,4,Group',
                                              'white,88,C,Small,5,Group'];




      end;



implementation

 {$R Pfmx.res}


procedure TPiano.play(KeyIndex:integer);
var
   audioAdd:string;
begin


tthread.CreateAnonymousThread(procedure
var
   audioAdd:string;
begin
 try


  audioAdd:=PreAudio[keyindex];

  if audioAdd<>'' then
     begin
      tthread.Synchronize(tthread.Current,procedure
       begin
       pianokey[keyindex].pAudio.Clear;
       pianokey[keyindex].pAudio.FileName:=audioAdd;
       pianokey[keyindex].pAudio.Play;
       end);
     end;


 except

 end;
 end).Start;

end;

function TPiano.GettimbreList():tstringlist;
var
  FS: TSearchRec;
  FPath: String;
  AddPath: string;

  timbrex,timbrey:single;
begin

  FPath := IncludeTrailingPathDelimiter(timbrePath);

  if FindFirst(FPath + '*.*', faAnyFile, FS) = 0 then
  begin
    repeat
    if (FS.Name <> '.') and (FS.Name <> '..') and
       ((FS.Attr and faDirectory) = faDirectory) then
        begin


              setlength(timbre,length(timbre)+1);
              with timbre[length(timbre)-1] do
                 begin
                    TimbreLabel:=TRadioButton.Create(backbox);
                    TimbreLabel.Parent:=backbox;
                    timbreLabel.Text:=fs.Name;
                    pretimbre:=FindPathFiles(FPath+fs.Name);
                    timbrelabel.Width:=150;

                    timbrex:=((length(timbre)-1) div 4) * 150+10;
                    timbrey:=((length(timbre)-1) mod 4) *20+30;
                    timbrelabel.Position.X:=timbrex;
                    timbrelabel.Position.y:=timbrey;
                    timbrelabel.OnChange:=onChange;
                    timbrelabel.Tag:=length(timbre)-1;

                 end;

        end;
    until FindNext(FS) <> 0;
    FindClose(FS);
  end;

      timbreCaption:=tlabel.Create(backbox);
      timbreCaption.Parent:=backbox;
      timbrecaption.Text:='Select Timbre:';
      timbrecaption.Position.X:=10;
      timbrecaption.Position.Y:=8;

end;



function TPiano.FindPathFiles(const APath: string; const APropty: String = '*.mp3'):tstringlist;
var
  FS: TSearchRec;
  FPath: String;
  AddPath: string;
begin
  result:=tstringlist.Create;
  FPath := IncludeTrailingPathDelimiter(APath);

  if FindFirst(FPath + APropty, faAnyFile, FS) = 0 then
  begin
    repeat
    if (FS.Name <> '.') and (FS.Name <> '..') and
       ((FS.Attr and faDirectory) <> faDirectory) then
       result.Add(FPath + FS.Name);
    until FindNext(FS) <> 0;
    FindClose(FS);
  end;
end;
constructor TPiano.Create(backG:TObject);
var
  tmpi:integer;
  WhiteCount,BlackCount:integer;
  WhiteLeft:single;

  const
     whiteWidth=30;
     blackWidth=20;
     Pianotop=150;
  procedure LoadImg(Bmp:tbitmap;imgname:string);

    var
      resStream: TResourceStream;
   begin

         resStream := TResourceStream.Create(HInstance, imgname, RT_RCDATA);
         if resStream.Size>0 then
             bmp.LoadFromStream(resStream);
         resStream.Free;

   end;
 function GetKeyName(iListIndex:integer):string;
 var
   tmpkey:tstringlist;
   keyName:string;
   function Getflag():string;
   var
     tmpj:integer;
     tmpjcs:integer;
      begin
          result:='';
          if strtoint(tmpkey[1])<40 then

             if strtoint(tmpkey[1])<28 then
                 tmpjcs:=-1
              else
                 tmpjcs:=0
          else
            tmpjcs:=2;
           for tmpj := tmpjcs to strtoint(tmpkey[4]) do
               begin

                result:=result+'.';
               end;
      end;
 begin
      tmpkey:=tstringlist.Create;
      tmpkey.DelimitedText:=keylist[iListIndex];
      keyName:=tmpkey[2];

      if strtoint(tmpkey[1])<40 then
         keyname:=keyname+#13+Getflag
      else
         keyname:=Getflag+#13+keyname;
      tmpkey.Free;

      result:=keyname;
 end;

 procedure drawTxt(bmp:tbitmap;orect:trectf;Txt:string;color:Tcolor=$ff000000);
 begin

     bmp.Canvas.BeginScene();

      bmp.Canvas.Font.Size:=10;
      bmp.Canvas.Font.Style:=[TFontStyle.fsBold];
      bmp.Canvas.Fill.Color:=color;
     bmp.Canvas.FillText(orect,txt,true,200,[],TTextAlign.Center,TTextAlign.Center);

      bmp.Canvas.EndScene;

 end;

begin
      timbrePath:=ExtractFilePath(ParamStr(0))+'\timbre\';
      preaudio:=tstringlist.create;
      backbox:=TRectangle.Create(TComponent(Backg));
      backbox.Parent:=tfmxobject(backg);
      backbox.Fill.Kind:=TBrushKind.None;
      backbox.Stroke.Kind:= TBrushKind.None;
      Whitecount:=0;
      BlackCount:=0;

     for tmpi := 0 to 87 do
         begin

              with  PianoKey[tmpi] do
                begin
                   keyButton:=timage.Create(backbox);
                   keybutton.Parent:= backbox;
                   keybutton.ClipChildren:=true;

                  keybutton.WrapMode:=TImageWrapMode.Center;

                  if pos('black',keylist[tmpi])=0 then
                     begin
                       keybutton.Width:=whiteWidth;
                       keybutton.Position.X:=(whiteWidth) * Whitecount+2;
                       keybutton.Position.y:=Pianotop;
                       keybutton.height:=125;
                       inc(Whitecount);
                       WhiteLeft:= keybutton.Position.x;
                       keybutton.SendToBack;
                       LoadImg(keybutton.Bitmap,'White');

                       DrawTxt(keybutton.Bitmap, trectf.Create(31, 210,60,250),GetKeyName(tmpi));
                       DrawTxt(keybutton.Bitmap, trectf.Create(0, 85,30,125),GetKeyName(tmpi));
                     end
                   else
                     begin

                       keybutton.Width:=blackWidth;
                       keybutton.Position.x:=WhiteLeft+2 +whiteWidth-blackWidth div 2-2  ;
                       keybutton.Position.y:=Pianotop;
                       keybutton.height:=70;
                       inc(BlackCount);
                       keybutton.BringToFront;

                       LoadImg(keybutton.Bitmap,'Black');
                     end;



                     keybutton.OnMouseDown:=mdown;
                     keybutton.OnMouseUp:=mup;
                     keybutton.OnClick:=keyclick;
                     keybutton.Tag:=tmpi;
                     paudio:=TMediaPlayer.Create(nil);


                end;



         end;


          backbox.Width:= PianoKey[87].keyButton.Position.x+whiteWidth+5;
          backbox.Height:=125+Pianotop;

         GettimbreList;
         timbre[0].TimbreLabel.IsChecked:=true

end;

procedure TPiano.PreLoadAudio(APath:string;const Eix:string='*.wav');

   function GetKeyName(inKeyName:string):string;
    begin
          result:=ChangeFileExt(ExtractFileName(inkeyName),'');
    end;
begin
      PreAudio:=(FindPathFiles(APath,Eix));

end;



procedure TPiano.MDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: single);
begin
     timage(sender).WrapMode:=TImageWrapMode.Original;
end;

procedure TPiano.MUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: single);
begin
     timage(sender).WrapMode:=TImageWrapMode.Center;
end;

procedure TPiano.KeyClick(Sender: TObject);
begin
     play(timage(sender).Tag);
end;

procedure TPiano.onChange(Sender: TObject);
begin

      preaudio.Text:=timbre[tRadioButton(sender).Tag].Pretimbre.text;
end;

end.
